#include "sgu.h"

SGU_NS_BEGIN



static char digitletter(unsigned int n)
{
	if(n<10) return '0'+n;
	if(n<36) return 'A'+n-10;
	return '?';
}



size_t utobase(unsigned int n, char * str, int base, size_t minwidth)
{
	ASSERT(inoc(base,1,36));
	
	char tmp[sizeof(n)*CHAR_BIT+1]; //1 for null terminator
	char * p = tmp;
	
	unsigned int m = n;
	for(;m;++p)
	{
		unsigned int module = m % base;		
		m /= base;
		*p = digitletter(module);
	}	
	
	char * pe = str+minwidth-(p-tmp);
	char * s = str;
	for(;s<pe;++s) *s = '0';
	for(;p>tmp;++s,--p) *s = *(p-1);

	if(s==str)
	{
		*s = '0';
		++s;
	}
		
	*s = 0;
	return (s-str);
}


size_t itod(int n, char * s, bool plus)
{
	if(n>0)
		
	{
		if(plus) *(s++)='+';
		return utod((unsigned int)n,s);
	}
		
	if(n<0)
	{
		*(s++)='-';
		return utod((unsigned int)(-n),s);
	}

	*(s++)='0';
	*s=0;

	return 1;
}


std::string itod(int n)
{
	char tmp[sizeof(n)*3+2];
	itod(n,tmp);
	return std::string(tmp);
}


size_t rtos(real x, char * s)
{
	ASSERT(sizeof(x)==8);	
	return sprintf(s,"%.15g",x);
}

std::string rtos(real x)
{
	char str[256];
	rtos(x,str);
	return std::string(str);
}

void trim(char * s, const char * pattern)
{
	char * p = s;
	while(*p) ++p;
	--p;
	while(p>=s)
	{
		if(strchr(pattern,*p)) *(p--) = '\0';
		else break;
	}
	size_t len = p-s+1;
		
	p = s;
	while(*p) if(!strchr(pattern,*p)) break;
	memmove(s,p,len-(p-s));
}

std::string trim(const std::string & s, const char * pattern)
{
	char * t = new char[s.size()+1];
	strcpy(t,s.data());
	trim(t,pattern);
	std::string retval = std::string(t);
	delete[] t;
	return retval; 
}

real stor(const char * s)
{
	return strtod(s,0);
}

unsigned int stou(const char * s, char ** endptr)
{
	if(isdigit(s[0])) return (unsigned int)strtoul(s,endptr,10);
	switch(s[0])
	{
		case '$' : return (unsigned int)strtoul(s+1,endptr,16);
		case '%' : return (unsigned int)strtoul(s+1,endptr,2);
		case 'o' : return (unsigned int)strtoul(s+1,endptr,8);
		default : THROWSGUFUNCEXCEPTION("/bad");
	}
	
	ASSERT(false);
	return 0;
}		

std::string ptoa(const void * p)
{
	char sk[sizeof(p)*2+16];
	snprintf(sk,DIM(sk),"%p",p);
	return std::string(sk);
}


std::string format(const char * frm, const std::vector<std::string> & dta)
{
	std::string str;
	
	size_t pos = 0;
	
	while(*frm)
	{
		if(*frm != '%')
		{
			str += (*frm);
			frm += 1;
			continue;
		};
  
		if(*(frm+1)=='$')
		{
			ASSERT(pos<dta.size());
			str += (dta[pos++]);
			frm += 2;
			continue;
		};

		if(*(frm+1)=='%')
		{
			str += '%';
			frm += 2;
			continue;
		};
	
		ASSERT(false);

	};

	ASSERT(pos==dta.size());

	return str;
}



//*/////////////////// Format

Format::Format(const char * str)
{
	_form = std::string(str);
}

Format::Format(const std::string & str)
{
	_form = str;
}

Format & Format::operator % (const char * str)
{
	_data.push_back(std::string(str));
	return *this;
}

Format & Format::operator % (const std::string & str)
{
	_data.push_back(str);
	return *this;
}

Format::operator std::string () const
{
	return format(_form.data(),_data);
}


std::vector<std::string> parse
(
	const std::string & src,
	bool usespc,
	const std::string & tok,
	bool toka,
	char sdl,
	bool sdla,
	char bsl,
	char com
)
{
	std::vector<std::string> array;
	
	#ifdef SGU_DEBUG
	if(usespc) ASSERT(src.find(' ')==std::string::npos);
	#endif
	
	array.clear();
	std::string build;
	int state = 1;

	CITERATE(std::string,it,src)	
	{
		char current = *it;
		
		switch(state)
		{
			case 1 : 
			{
				if(current==com) return array;
				if(usespc) if(current==' ') break;
				if(strchr(tok.data(),current))
				{
					array.push_back(build);
					build.clear();
					if(toka) array.push_back(std::string(1,current));
					break;
				};
				if(current==sdl)
				{
					if(sdla) build += current;
					state = 4;
					break;
				};
				build += current;
				state = 2;
			}; break;

			case 2 :
			{
				if(current==com)
				{
					array.push_back(build);
					return array;
				};
				if(usespc) if(current==' ')
				{
					state = 3;
					break;
				};
				if(strchr(tok.data(),current))
				{
					array.push_back(build);
					build.clear();
					if(toka) array.push_back(std::string(1,current));
					state = 1;
					break;
				};
				if(current==sdl)
				{
					array.push_back(build);
					build.clear();
					if(sdla) build += current;
					state = 4;
					break;
				};
				build += current;

			}; break;

			case 3 :
			{
				if(current==com)
				{
					array.push_back(build);
					return array;
				};
				if(usespc) if(current==' ') break;
				if(strchr(tok.data(),current))
				{
					array.push_back(build);
					build.clear();
					if(toka) array.push_back(std::string(1,current));
					state = 1;
					break;
				};
				if(current==sdl)
				{
					array.push_back(build);
					build.clear();
					if(sdla) build += current;
					state = 4;
					break;
				};

				array.push_back(build);
				build.clear();
				build += current;
				state = 2;
			}; break;

			case 4 :
			{
				if(current==sdl)
				{
					if(sdla) build += current;
					array.push_back(build);
					build.clear();
					state = 1;
					break;
				};
				if(current==bsl)
				{
					state = 5;
					break;
				};
				build += current;
			}; break;

			case 5 :
			{
				build += current;
				state = 4;
			}; break;
		
			default : ASSERT(false);
		};
	};

	if(state==2 || state==3) array.push_back(build);

	return array;
}


void strupr(char * str)
{
	while(*str)
	{
		*str = (char)::toupper(*str);
		++str;
	}
}

void strlwr(char * str)
{
	while(*str)
	{
		*str = (char)::tolower(*str);
		++str;
	}
}

void makeupper(std::string & str)
{
	size_t n = str.size();
	LOOP(size_t,j,n) str.at(j) = (char)::toupper(str.at(j));
}

void makelower(std::string & str)
{
	size_t n = str.size();
	LOOP(size_t,j,n) str.at(j) = (char)::tolower(str.at(j));
}


std::string toupper(const std::string & a)
{
	std::string b;
	CITERATE(std::string,it,a) b += (char)::toupper(*it);
	return b;
}

std::string tolower(const std::string & a)
{
	std::string b;
	CITERATE(std::string,it,a) b += (char)::tolower(*it);
	return b;
}


std::string rjus(const std::string & a, std::string::size_type n, char c)
{
	std::string::size_type w = a.size();
	if(w>=n) return a;
	return std::string(n-w,c)+a;
}

std::string ljus(const std::string & a, std::string::size_type n, char c)
{
	std::string::size_type w = a.size();
	if(w>=n) return a;
	return a+std::string(n-w,c);
}


SGU_NS_END
